using Sandia.MVCFramework.Common;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace Sandia.MVCFramework.Request
{
    /// <summary>
    /// A general purpose IRequestParameterFactory that uses reflection to
    /// instantiate parameters.
    /// </summary>
    public class StandardRequestParameterFactory : IRequestParameterFactory
    {
        #region IRequestParameterFactory Members

        /// <summary>
        /// Create a request parameter of the given type using the given data.
        /// </summary>
        /// <param name="parameterType">The type of parameter to create.</param>
        /// <param name="data">The data that the parameter will carry.</param>
        /// <returns>The new parameter.</returns>
        public IRequestParameter CreateRequestParameter(
            Type parameterType, 
            object data)
        {
            // Make sure that this is an IRequestParameter.
            //
            if (!typeof(IRequestParameter).IsAssignableFrom(parameterType))
            {
                LoggingTools.SendToLog(
                    parameterType.ToString() +
                    " does not inherit from IRequestParameter.",
                    LoggingCategories.ERROR,
                    100);
                return null;
            }

            // Create the parameter

            // In order to instantiate something of type 'parameterType'
            // we have to use reflection to determine if the
            // type has the correct constructor.
            //
            Type[] constructorParameters = { data.GetType() }; 
            ConstructorInfo parameterConstructorInfo =
                parameterType.GetConstructor(constructorParameters);

            // If type 'parameterType' does not have a single parameter 
            // constructor.
            //
            if (parameterConstructorInfo == null)
            {
                LoggingTools.SendToLog(
                    "Type " +
                    parameterType.FullName +
                    " does not have a single parameter constructor with type " +
                    data.GetType().FullName + ".",
                    LoggingCategories.ERROR,
                    100);
                return null;
            }

            // Actually call the constructor using reflection
            //
            IRequestParameter parameter =
                (IRequestParameter)parameterConstructorInfo.Invoke(
                    new object[] { data });

            return parameter;
        }

        #endregion
    }
}
